/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package asis;

import asis.ini.INI;
import java.io.IOException;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import skyproc.*;
import skyproc.gui.SPProgressBarPlug;

/**
 *
 * @author pc tech
 */
public class AutomaticPerks {

    public void addPerks() {
        internalAddPerks();
    }

    public void addPerks(ASIS a) {
        if (a.getModExclusions() != null) {
            NPCModExclusions.addAll(a.getModExclusions());
            perkModExclusions.addAll(a.getModExclusions());
        }

        internalAddPerks();
    }

    private void internalAddPerks() {
        SPProgressBarPlug.setStatus("Automatic Perks: Starting Patch");
        SPProgressBarPlug.incrementBar();
        Mod merger = new Mod("TmpMerger", false);
        merger.addAsOverrides(SPGlobal.getDB());

        processINI();
        getSkillIndices();
        getPerkLists(merger);
        addPerksToNPCs(merger);
        addPerksToFollowers(merger);
    }

    private void addPerksToNPCs(Mod merger) {
        SPProgressBarPlug.setStatus("Automatic Perks: Adding Perks to NPCs");
        SPProgressBarPlug.incrementBar();

        int conditionsMet;
        int temp;
        int perkNum;
        Skill tempSkill;
        boolean npcInclude;
        boolean perkInclude;

        ArrayList<Perk> tempToRemove = new ArrayList<>();

        for (Perk p : perks) {
            perkInclude = getValidPerk(p);
            if (!perkInclude) {
                tempToRemove.add(p);
            }
        }

        perks.removeAll(tempToRemove);

        for (NPC_ n : merger.getNPCs()) {
            npcInclude = getValidNPC(n);
            if (npcInclude) {

                if (!n.getPerks().isEmpty()) {
                    perkNum = n.getPerks().get(0).getNum();
                } else {
                    perkNum = 0;
                }
                for (Perk p : perks) {
                    conditionsMet = 0;
                    for (int i = 0; i < p.getNumConditionals(); i++) {
                        temp = p.getPerkType(i);
                        if (temp != -1) {
                            tempSkill = perkSettingsMap.get(temp);
                            if (n.get(tempSkill) > p.getPerkLevel(i)) {
                                conditionsMet++;
                            }
                        }

                        if (conditionsMet >= p.getNumConditionals()) {
                            n.addPerk(p.getPerkForm(), perkNum);
                            if (nextPerksMap.containsKey(p.getPerkForm())) {
                                n.removePerk(nextPerksMap.get(p.getPerkForm()));
                            }
                            SPGlobal.getGlobalPatch().addRecord(n);
                        }
                    }
                }
            }
        }

        //Clean-up NPC's from excluded mods.  This is done as blocking the import 
        // could cause previous NPC's to override an excluded mods NPC's.
        String list;
        Mod tempMod;
        GRUP patchGRUP = SPGlobal.getGlobalPatch().getNPCs();
        for (int i = 0; i < NPCModExclusions.size(); i++) {
            list = (String) NPCModExclusions.get(i);
            try {
                tempMod = SPGlobal.getDB().getMod(new ModListing(list));
                for (NPC_ n : tempMod.getNPCs()) {
                    patchGRUP.removeRecord(n.getForm());
                }
            } catch (Exception e) {
                //Do nothing, probably doesn't have the mod in the exclusions.
            }
        }
    }

    private void addPerksToFollowers(Mod merger) {
        SPProgressBarPlug.setStatus("Automatic Perks: Adding Perks to Followers");
        SPProgressBarPlug.incrementBar();

        int conditionsMet;
        int temp;
        int perkNum;
        Skill tempSkill;
        boolean npcInclude;
        boolean perkInclude;
        FormID hirelingFaction = new FormID("0BCC9A", SPGlobal.getDB().getMod(new ModListing("Skyrim", true)).getInfo());
        FormID followerFaction = new FormID("05C84D", SPGlobal.getDB().getMod(new ModListing("Skyrim", true)).getInfo());

        for (NPC_ n : merger.getNPCs()) {
            npcInclude = getValidFollower(n, followerFaction, hirelingFaction);

            if (npcInclude) {

                if (!n.getPerks().isEmpty()) {
                    perkNum = n.getPerks().get(0).getNum();
                } else {
                    perkNum = 0;
                }
                for (Perk p : perks) {

                    /*
                     * if (n.getEDID().contains("EncDremoraWarlock06") &&
                     * p.getEDID().contains("AugmentedShock60")) { int abc = 0;
                     * }
                     */
                    conditionsMet = 0;
                    perkInclude = getValidPerk(p);
                    if (perkInclude) {
                        for (int i = 0; i < p.getNumConditionals(); i++) {
                            temp = p.getPerkType(i);
                            if (temp != -1) {
                                tempSkill = perkSettingsMap.get(temp);
                                if (n.get(tempSkill) > p.getPerkLevel(i)) {
                                    conditionsMet++;
                                }
                            }
                        }
                        if (conditionsMet >= p.getNumConditionals()) {
                            n.addPerk(p.getPerkForm(), perkNum);
                            if (nextPerksMap.containsKey(p.getPerkForm())) {
                                n.removePerk(nextPerksMap.get(p.getPerkForm()));
                            }
                            SPGlobal.getGlobalPatch().addRecord(n);
                        }
                    }
                }
            }
        }
    }

    private void getPerkLists(Mod merger) {
        SPProgressBarPlug.setStatus("Automatic Perks: Mapping Perks");
        SPProgressBarPlug.incrementBar();
        Perk tempPerk = null;
        FormID nextPerkForm;
        int numConditions;
        boolean perkUsed;
        for (PERK p : merger.getPerks()) {
            perkUsed = false;
            numConditions = 0;
            for (int i = 0; i < p.getSizeOfCTDAs(); i++) {
                if (p.getComparison(i) == 96 && p.getComparisonFunction(i) == 277 && !perkUsed) {
                    if (p.getNextPerkForm() != null) {
                        nextPerkForm = p.getNextPerkForm();
                        nextPerksMap.put(nextPerkForm, p.getForm());
                    } else {
                        nextPerkForm = p.getForm();
                    }
                    tempPerk = new Perk(p, p.getActorValue(i), p.getComparisonValue(i), nextPerkForm);
                    perks.add(tempPerk);
                    numConditions++;

                } else if (p.getComparison(i) == 96 && p.getComparisonFunction(i) == 277 && perkUsed) {
                    tempPerk.addConditional(p.getActorValue(i), p.getComparisonValue(i));
                }
            }
        }
    }

    private boolean getValidFollower(NPC_ n, FormID followerFaction, FormID hirelingFaction) {

        boolean npcExclude = false;
        boolean npcInclude = false;

        for (int i = 0; i < n.getFactions().size(); i++) {
            if (n.getFactions().get(i).getForm().get() == followerFaction.get()
                    || n.getFactions().get(i).getForm().get() == hirelingFaction.get()) {
                npcInclude = true;
            }
        }

        String list;
        for (int i = 0; i < NPCModExclusions.size(); i++) {
            list = (String) NPCModExclusions.get(i);
            if (n.getFormMaster().equals(new ModListing(list))) {
                npcExclude = true;
                break;
            }
        }

        if (npcInclude && !npcExclude) {
            return true;
        } else {
            return false;
        }
    }

    private boolean getValidNPC(NPC_ n) {
        boolean npcExclude = false;
        boolean npcInclude = false;
        String list;
        String edid = n.getEDID().toUpperCase();

        if (npcInclusions.isEmpty()) {
            npcInclude = true;
        }
        if (!npcInclude) {
            for (int i = 0; i < npcInclusions.size(); i++) {
                list = ((String) npcInclusions.get(i));
                if (edid.contains(list)) {
                    npcInclude = true;
                    break;
                }
            }
        }
        if (npcExclusions.isEmpty() && NPCModExclusions.isEmpty()) {
            npcExclude = false;
        }
        if (npcInclude && !npcExclude) {
            for (int i = 0; i < npcExclusions.size(); i++) {
                list = ((String) npcExclusions.get(i));
                if (edid.contains(list)) {
                    npcExclude = true;
                    break;
                }
            }
            for (int i = 0; i < NPCModExclusions.size(); i++) {
                list = (String) NPCModExclusions.get(i);
                if (n.getFormMaster().equals(new ModListing(list))) {
                    npcExclude = true;
                    break;
                }
            }
        }

        if (npcInclude && !npcExclude) {
            return true;
        } else {
            return false;
        }
    }

    private boolean getValidPerk(Perk p) {
        boolean perkExclude = false;
        boolean perkInclude = false;
        String list;
        String edid = p.getEDID().toUpperCase();

        if (perkInclusions.isEmpty()) {
            perkInclude = true;
        }
        if (!perkInclude) {
            for (int i = 0; i < perkInclusions.size(); i++) {
                list = ((String) perkInclusions.get(i));
                if (edid.contains(list)) {
                    perkInclude = true;
                    break;
                }
            }
        }
        if (perkExclusions.isEmpty() && perkExclusionsStartsWith.isEmpty() && perkModExclusions.isEmpty()) {
            perkExclude = false;
        } else if (perkInclude) {
            for (int i = 0; i < perkExclusionsStartsWith.size(); i++) {
                list = ((String) perkExclusionsStartsWith.get(i));
                if (edid.startsWith(list)) {
                    perkExclude = true;
                    break;
                }
            }

            if (!perkExclude) {
                for (int i = 0; i < perkExclusions.size(); i++) {
                    list = ((String) perkExclusions.get(i));
                    if (edid.contains(list)) {
                        perkExclude = true;
                        break;
                    }
                }
            }
            if (!perkExclude) {
                for (int i = 0; i < perkModExclusions.size(); i++) {
                    list = (String) perkModExclusions.get(i);
                    if (p.getModMaster().equals(new ModListing(list))) {
                        perkExclude = true;
                        break;
                    }
                }
            }
        }
        if (perkInclude && !perkExclude) {
            return true;
        } else {
            return false;
        }
    }

    private void getSkillIndices() {
        int i = 6;
        for (Skill s : Skill.values()) {
            perkSettingsMap.put(i, s);
            i++;
        }
    }

    private void processINI() {
        SPProgressBarPlug.setStatus("Automatic Perks: Processing INI");
        SPProgressBarPlug.incrementBar();
        //Sets up the file reader for the ini file.
        INI ini = null;

        //Sets up the file reader for the ini file.
        try {
            ini = new INI("AutomaticPerks.ini");
        } catch (IOException ex) {
            Logger.getLogger(NPCPotions.class.getName()).log(Level.SEVERE, null, ex);
        }

        Collection<INI.IniSectionHead> sections = getSectionList();

        ini.addSection(sections);

        try {
            ini.readData();
        } catch (IOException ex) {
            Logger.getLogger(NPCPotions.class.getName()).log(Level.SEVERE, null, ex);
        }

        initializeLists(ini);
    }

    private Collection<INI.IniSectionHead> getSectionList() {
        Collection<INI.IniSectionHead> sectionList = new ArrayList<>();

        for (IniSection currentSection : IniSection.values()) {
            sectionList.add(new INI.IniSectionHead(currentSection.getName(), currentSection.getFormat()));
        }

        return sectionList;
    }

    private void initializeLists(INI ini) {
        npcInclusions = (ArrayList) ini.getCollection(new INI.IniSectionHead(IniSection.NPCINCLUSIONS.getName(),
                IniSection.NPCINCLUSIONS.getFormat()));
        for (int i = 0; i < npcInclusions.size(); i++) {
            npcInclusions.set(i, ((String) npcInclusions.get(i)).toUpperCase());
        }
        npcExclusions = (ArrayList) ini.getCollection(new INI.IniSectionHead(IniSection.NPCEXCLUSIONS.getName(),
                IniSection.NPCEXCLUSIONS.getFormat()));
        for (int i = 0; i < npcExclusions.size(); i++) {
            npcExclusions.set(i, ((String) npcExclusions.get(i)).toUpperCase());
        }
        NPCModExclusions.addAll((ArrayList) ini.getCollection(new INI.IniSectionHead(IniSection.NPCMODEXCLUSIONS.getName(),
                IniSection.NPCMODEXCLUSIONS.getFormat())));

        perkExclusions = (ArrayList) ini.getCollection(new INI.IniSectionHead(IniSection.PERKEXCLUSIONSCONTAINS.getName(),
                IniSection.PERKEXCLUSIONSCONTAINS.getFormat()));
        for (int i = 0; i < perkExclusions.size(); i++) {
            perkExclusions.set(i, ((String) perkExclusions.get(i)).toUpperCase());
        }
        perkExclusionsStartsWith = (ArrayList) ini.getCollection(new INI.IniSectionHead(IniSection.PERKEXCLUSIONSSTARTSWITH.getName(),
                IniSection.PERKEXCLUSIONSSTARTSWITH.getFormat()));
        for (int i = 0; i < perkExclusionsStartsWith.size(); i++) {
            perkExclusionsStartsWith.set(i, ((String) perkExclusionsStartsWith.get(i)).toUpperCase());
        }
        perkModExclusions.addAll((ArrayList) ini.getCollection(new INI.IniSectionHead(IniSection.PERKMODEXCLUSIONS.getName(),
                IniSection.PERKMODEXCLUSIONS.getFormat())));
        perkInclusions = (ArrayList) ini.getCollection(new INI.IniSectionHead(IniSection.PERKINCLUSIONS.getName(),
                IniSection.PERKINCLUSIONS.getFormat()));
        for (int i = 0; i < perkInclusions.size(); i++) {
            perkInclusions.set(i, ((String) perkInclusions.get(i)).toUpperCase());
        }
    }

    private enum IniSection {

        PERKSETTINGS(INI.IniDataFormat.KEY_VALUE, "PERKSETTINGS"),
        NPCINCLUSIONS(INI.IniDataFormat.VALUE, "NPCINCLUSIONS"),
        NPCEXCLUSIONS(INI.IniDataFormat.VALUE, "NPCEXCLUSIONS"),
        NPCMODEXCLUSIONS(INI.IniDataFormat.VALUE, "NPCMODEXCLUSIONS"),
        PERKEXCLUSIONSCONTAINS(INI.IniDataFormat.VALUE, "PERKEXCLUSIONSCONTAINS"),
        PERKEXCLUSIONSSTARTSWITH(INI.IniDataFormat.VALUE, "PERKEXCLUSIONSSTARTSWITH"),
        PERKMODEXCLUSIONS(INI.IniDataFormat.VALUE, "PERKMODEXCLUSIONS"),
        PERKINCLUSIONS(INI.IniDataFormat.VALUE, "PERKINCLUSIONS");
        private INI.IniDataFormat format;
        private String name;

        IniSection(INI.IniDataFormat format, String name) {
            this.format = format;
            this.name = name;
        }

        String getName() {
            return name;
        }

        INI.IniDataFormat getFormat() {
            return format;
        }
    }
    static String settingType = null;
    static String settingValue = null;
    static int perkLevel;
    static Skill spellType;
    static int[] skillLevels = {0, 0, 0, 0, 0};
    static ArrayList npcInclusions = new ArrayList<>(0);
    static ArrayList npcExclusions = new ArrayList<>(0);
    static ArrayList NPCModExclusions = new ArrayList<>(0);
    static ArrayList perkInclusions = new ArrayList<>(0);
    static ArrayList perkExclusions = new ArrayList<>(0);
    static ArrayList perkExclusionsStartsWith = new ArrayList<>(0);
    static ArrayList perkModExclusions = new ArrayList<>(0);
    static ArrayList perkSettings = new ArrayList<>(0);
    ArrayList<FormID> npcBlockList = new ArrayList<>();
    ArrayList<FormID> spellBlockList = new ArrayList<>();
    static ArrayList<Perk> perks = new ArrayList<>();
    static Map<Integer, Skill> perkSettingsMap = new LinkedHashMap<>();
    static Map<FormID, FormID> nextPerksMap = new HashMap<>();
    public static int numProgressSections = 5;
}